package nexus.com.grid
{
	import com.ux.event.DragBarEvent;
	
	import flash.display.Graphics;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import nexus.com.container.ScrollContainer;
	import nexus.event.ListEvent;
	
	
	[Event(name="listSelectionChange", type="nexus.event.ListEvent")]
	
	
	
	public class Grid extends ScrollContainer
	{
		
		//-----------------------------------------------------------------------------------
		//
		// private
		//
		//-----------------------------------------------------------------------------------
		private var _dataProvider : Array;
		private var _list : Array = [];
		private var _gcList : Array = [];
		private var _columns : Array = [];
		private var _columnsWids : Array = [];
		private var _selectedIndex : int = -1;
		private var _selectedData : Object = null;
		private var _gridHeader : GridHeader;
		private var _lineRowLayer : Shape;
		private var _lineColumnLayer : Shape;
		private var _setResizeToContent : Boolean = false;
		private var _rowCount : int = 0;
		private var _headerHeight : Number = 0;
		private var _rowHeight : Number = 0; // 아이탬 0 번의 기본 viewHeight
		private var _extraItemNum : int = 6; // 화면을 벗어난 여유분 아이템 갯수 - 짝수 권장.
		private var _isViewColumnLine : Boolean = true;
		private var _isViewRowLine : Boolean = true;
		
		//-----------------------------------------------------------------------------------
		//
		// protected vars
		//
		//-----------------------------------------------------------------------------------
		
		
		//-----------------------------------------------------------------------------------
		//
		// public vars
		//
		//-----------------------------------------------------------------------------------
		
		
		
		//-----------------------------------------------------------------------------------
		//
		// constructor
		//
		//-----------------------------------------------------------------------------------
		public function Grid()
		{
			super();
			
			_lineRowLayer = new Shape();
			addElement( _lineRowLayer );
			
			_lineColumnLayer = new Shape();
			addChild( _lineColumnLayer );
		}
		
		
		//-----------------------------------------------------------------------------------
		//
		// setter / getter
		//
		//-----------------------------------------------------------------------------------
		
		public function set header( clip : GridHeader ):void
		{
			if( _gridHeader && this.contains( _gridHeader ) )
			{
				this.removeChild( _gridHeader );
				_gridHeader = null;
			}
			
			_gridHeader = clip;
			this.addChild( _gridHeader );
			headerHeight = _gridHeader.viewHeight;
			
			// 타이틀 영역만큼 마스크 패딩을 준다.
			super.maskPaddingTop = _headerHeight;
		}
		
		public function get header():GridHeader
		{
			if( _gridHeader == null )
			{
				// 타이틀을 생성하고.
				_gridHeader = new GridHeader();
				addChild( _gridHeader );
				
				_headerHeight = _gridHeader.viewHeight;
				// 타이틀 영역만큼 마스크 패딩을 준다.
				super.maskPaddingTop = _headerHeight
			}
			
			return _gridHeader;
		}
		
		
		
		public function get isViewRowLine():Boolean
		{
			return _isViewRowLine;
		}
		
		public function set isViewRowLine(value:Boolean):void
		{
			_isViewRowLine = value;
		}
		
		public function get isViewColumnLine():Boolean
		{
			return _isViewColumnLine;
		}
		
		public function set isViewColumnLine(value:Boolean):void
		{
			_isViewColumnLine = value;
		}
		
		public function get columnsWids():Array
		{
			return _columnsWids;
		}
		
		public function set columnsWids(value:Array):void
		{
			_columnsWids = value;
		}
		
		public function get extraItemNum():int
		{
			return _extraItemNum;
		}
		
		public function set extraItemNum(value:int):void
		{
			_extraItemNum = value;
		}
		
		public function get rowHeight():Number
		{
			return _rowHeight;
		}
		
		public function set rowHeight(value:Number):void
		{
			_rowHeight = value;
		}
		
		public function get headerHeight():Number
		{
			return _headerHeight;
		}
		
		public function set headerHeight(value:Number):void
		{
			_headerHeight = value;
			this.header.viewHeight = _headerHeight;
			this.maskPaddingTop = _headerHeight;
		}
		
		public function get rowCount():int
		{
			return _rowCount;
		}
		
		public function set rowCount(value:int):void
		{
			setResizeToContent = false;
			_rowCount = value;
			this.viewHeight = (_rowCount*rowHeight) + paddingTop + paddingBottom + maskPaddingTop + maskPaddingBottom;
			super.resetScroll();
			
		}
		
		public function get setResizeToContent():Boolean
		{
			return _setResizeToContent;
		}
		
		public function set setResizeToContent(value:Boolean):void
		{
			_setResizeToContent = value;
			
		}
		
		public function get columns():Array
		{
			return _columns;
		}
		
		public function set columns(value:Array):void
		{
			_columns = value;
			if( _dataProvider != null )
			{
				var len:int = _list.length;
				for (var i:int = 0; i < len; i++) 
				{
					_list[ i ].columns = _columns;
				}
			}
			
			header.columns = _columns;
			
		}
		
		public function get selectedData():Object
		{
			return _selectedData;
		}
		
		public function set selectedData(value:Object):void
		{
			_selectedData = value;
			
		}
		
		public function get selectedIndex():int
		{
			return _selectedIndex;
		}
		
		public function set selectedIndex(value:int):void
		{
			_selectedIndex = value;
			
		}
		
		public function set dataProvider( data : Array ):void
		{
			_dataProvider = data;
			updateDisplayList();
		}
		
		public function get dataProvider():Array
		{
			if( _dataProvider == null ) _dataProvider = [];
			return _dataProvider;
		}
		
		public function get measuredHeight():Number
		{
			return (_dataProvider.length*rowHeight) + paddingTop + paddingBottom + maskPaddingTop + maskPaddingBottom;
		}
		
		
		
		
		
		
		//-----------------------------------------------------------------------------------
		//
		// public function
		//
		//-----------------------------------------------------------------------------------
		
		
		override public function updateDisplayList():void
		{
			super.updateDisplayList();
			
			header.x = paddingLeft;
			header.y = paddingTop;
			
			if( _dataProvider != null )
			{
				updateItemList();
			}
			
			checkScrollPolicy();
		}
		
		//-----------------------------------------------------------------------------------
		//
		// protected function
		//
		//-----------------------------------------------------------------------------------
		
		
		/**
		 * 화면 사이즈 + extraItemNum 만큼의 리스트 유지를 위한 메서드
		 */		
		protected function updateItemList():void
		{
			if( _setResizeToContent == true && rowHeight != 0 && measuredHeight != this.viewHeight )
			{
				this.viewHeight = measuredHeight;
			}
			
			// 실제 컬럼 너비를 다시 연산.
			calculateColumnWids();
			header.columnsWids = _columnsWids;
			
			
			// 리스트에서 전부 가비지로 이동.
			this.removeAllElement();
			addElement( _lineRowLayer );
			if( _list.length > 0 )
			{
				for( var idx : String in _list )
				{
					_gcList.push( _list.shift().reset() );
				}
			}
			
			
			var g : Graphics;
			g = _lineRowLayer.graphics;
			g.clear();
			
			
			
			// 만약 데이터가 없을경우 extraItemNum 을 0으로 해준다.
			var tempExtraItemNum : Number = ( dataProvider.length == 0 ) ? 0 : extraItemNum; 
			
			// 데이터 셋팅
			var item : GridItem;
			var dataStartNum : int = Math.ceil( (-wrapperContainer.y)/rowHeight )- Math.ceil( tempExtraItemNum/2 );
			var maxHeight : Number = this.maskClip.height + ( rowHeight*tempExtraItemNum );
			var len:int = Math.ceil( maxHeight/rowHeight );
			dataStartNum = Math.max( Math.min( dataStartNum , dataProvider.length-len ), 0 );
			for (var i:int = 0; i < len; i++) 
			{
				item = getItem() as GridItem;
				item.columnsWids = _columnsWids;
				itemDefaultSetting( item, _dataProvider[ i+dataStartNum ] );
				item.y = int( rowHeight*(dataStartNum+i) );
				
				var lc : Point = new Point( item.x,item.y );
				
				item.apply();
				
				addElement( item );
				_list.push( item );
				
				if( _isViewRowLine )
				{
					// 로우별 가로라인 그리기
					g.lineStyle( 1, 0xcccccc );
					g.moveTo( item.x, item.y+item.height );
					g.lineTo( item.viewWidth, item.y + item.height );
				}
			}
			
			// 컨텐츠 컨테이너의 가상 높이 셋팅 및 선텍 인덱스 컨트롤.
			this.wrapContainerHeight = dataProvider.length * rowHeight;
			listItemSelectControl();
			
			g = _lineColumnLayer.graphics;
			g.clear();
			
			// 컬럼별 세로라인 그리기
			if( _isViewColumnLine )
			{
				var sum : Number = 0;
				len = _columnsWids.length;
				for( i = 0 ; i<len-1; ++i )
				{
					sum += _columnsWids[ i ];
					g.lineStyle( 1, 0xcccccc );
					g.moveTo( sum, this.y+paddingTop );
					g.lineTo( sum, this.y+viewHeight );
				}
			}
			
			
			// 타이틀 영역 수정.
			header.viewWidth = ( isNeedVscroll ) ? viewWidth-verticalScroll.width-paddingLeft-paddingRight : viewWidth-paddingLeft-paddingRight;
			header.apply();
			
			// 헤더는 NXSprite 의 보더 아래 인덱스로 셋팅되어야 함.
			setChildIndex( header, getChildIndex( wrapperContainer )+1 );
			
			
			// 라인을 가장 상위 인덱스로 셋팅
			if( _isViewRowLine ) setElementIndex( _lineRowLayer, numElemnt-1 );
			if( _isViewColumnLine ) setChildIndex( _lineColumnLayer, getChildIndex( header )+1 ); 
		}
		
		
		private function calculateColumnWids():void
		{
			// 기본적인 _columnsWids 구하기
			_columnsWids = [];
			for each( var column : GridColumn in _columns )
			{
				_columnsWids.push( column.width );
			}
			
			// -1 로 들어온 너비에 대해 기본너비 구하기.
			var sum : Number = 0;
			var countDefaultWid : Number = 0;
			for each( var num : Number in _columnsWids )
			{
				if( num != -1 ) sum += num;
				else countDefaultWid++;
			}
			
			
			
			// 실제 컬럼의 너비 셋팅
			var tempColumnWids : Array = [];
			
			if( countDefaultWid != 0 ) // -1값이 1개라도 있으면,
			{
				var defaultWid : Number = Math.floor( ( viewWidth-sum ) / countDefaultWid );
				for each( num in _columnsWids )
				{
					if( num == -1 ) tempColumnWids.push( defaultWid );
					else tempColumnWids.push( num );
					
				}
			}
			else // -1값이 1개도 없으면 extra Width 를 구한다.
			{
				var len : int = _columnsWids.length;
				var extraWid : Number = viewWidth-sum;
				for each( num in _columnsWids )
				{
					tempColumnWids.push( Math.floor( num + extraWid*( num/sum ) ) );
				}
			}
			
			// _columnsWids 를 연산결과값으로 대체.
			_columnsWids = tempColumnWids;
			
		}	
		
		/**
		 * @return list 재활용 메서드 
		 */		
		protected function getItem():*
		{
			if( _gcList.length > 0 )
			{
				return _gcList.pop();
			}
			
			var item : GridItem = new GridItem();
			return item;
		}
		
		/**
		 * 리스트 아이템 기본 셋팅.
		 * @param __item 리스트 아이템
		 * @param dp
		 */		
		protected function itemDefaultSetting( __item : GridItem, dp : Object ):void
		{
			__item.viewWidth = ( isNeedVscroll ) ? viewWidth-verticalScroll.width-paddingLeft-paddingRight : viewWidth-paddingLeft-paddingRight;
			__item.columns = _columns;
			__item.data = dp;
			
			
			if( dp == null )
			{
				//				__item.buttonMode = false;
				__item.removeEventListener(MouseEvent.ROLL_OVER, onItemOver );
				__item.removeEventListener(MouseEvent.ROLL_OUT, onItemOut );
				__item.removeEventListener(MouseEvent.CLICK, onItemClick );
				__item.removeEventListener(MouseEvent.MOUSE_DOWN, onItemDown );
			}
			else
			{
				//				__item.buttonMode = true;
				__item.addEventListener(MouseEvent.ROLL_OVER, onItemOver );
				__item.addEventListener(MouseEvent.ROLL_OUT, onItemOut );
				__item.addEventListener(MouseEvent.CLICK, onItemClick );
				__item.addEventListener(MouseEvent.MOUSE_DOWN, onItemDown );
			}
		}
		//-----------------------------------------------------------------------------------
		//
		// private function
		//
		//-----------------------------------------------------------------------------------
		
		private function getIndexByData( data:Object ):int
		{
			var len:int = _dataProvider.length;
			for (var i:int = 0; i < len; i++) 
			{
				if( _dataProvider[ i ] == data ) return i;
			}
			
			return -1;
		}
		
		
		private function listItemSelectControl():void
		{
			var len:int = _list.length;
			for (var i:int = 0; i < len; i++) 
			{
				if( _list[ i ].data != null && _list[ i ].data == _selectedData ) _list[ i ].ON();
				else _list[ i ].OFF();
			}
		}
		
		//-----------------------------------------------------------------------------------
		//
		// event handler
		//
		//-----------------------------------------------------------------------------------
		
		override protected function onVScrollEvent(e:DragBarEvent):void
		{
			super.onVScrollEvent( e );
			updateItemList();
		}
		
		// down 에서 인덱스를 컨트롤하고, 아이템 안의 버튼 클릭 보다 빠른 인덱스 셋팅을 위하여, 
		protected function onItemDown(e:MouseEvent):void
		{
			var idx : int = getIndexByData( e.currentTarget.data );
			_selectedIndex = idx;
			_selectedData = e.currentTarget.data;
			
			listItemSelectControl();
		}
		
		// 클릭시점에서 이벤트 날림. 
		protected function onItemClick(e:MouseEvent):void
		{
			var le : ListEvent = new ListEvent( ListEvent.LIST_SELECTION_CHANGE );
			le.data = e.currentTarget.data;
			dispatchEvent( le );
		}
		
		protected function onItemOut(e:MouseEvent):void
		{
			if( e.currentTarget.data != _selectedData )
			{
				e.currentTarget.OFF();
			}
		}
		
		protected function onItemOver(e:MouseEvent):void
		{
			e.currentTarget.ON();
		}
		
		
		//-----------------------------------------------------------------------------------
		//
		// destory
		//
		//-----------------------------------------------------------------------------------
		override public function destory():void
		{
			super.destory();
		}
		
		
		
		
		
		
		
		
	}
}